/*
 requestAnimationFrame 采用系统时间间隔来执行回调函数，保持最佳绘制效率，不会因为间隔时间的过短，造成过度绘制，增加页面开销，也不会因为间隔时间过长，造成动画卡顿，不流程，影响页面美观。
 requestAnimationFrame的基本思想：让页面重绘的频率和刷新频率保持同步，即每 1000ms / 60 = 16.7ms执行一次。由于每次执行动画帧回调是由浏览器重回频率决定的，因此不需要像 setTimeout 那样传递时间间隔，而是浏览器通过系统获取并使用显示器刷新频率。
requestAnimationFrame 自带节流功能，例如在某些高频事件（resize，scroll 等）中，requestAnimationFrame 依据系统时间间隔来调用回调，可以防止在一个刷新间隔内发生多次函数执行。
requestAnimationFrame 延时效果是精确的，即在每次页面重绘前必会清空一次动画帧回调队列。(setTimeout 任务被放进异步队列中，只有当主线程上的任务执行完以后，才会去检查该队列的任务是否需要开始执行，造成时间延时)。
requestAnimationFrame 会把每一帧中的所有DOM操作集中起来，在一次重绘或回流中完成。
setTimeout 的执行只是在内存中对图像属性进行改变，这个改变必须要等到下次浏览器重绘时才会被更新到屏幕上。如果和屏幕刷新步调不一致，就可能导致中间某些帧的操作被跨越过去，直接更新下下一帧的图像，即掉帧。使用 requestAnimationFrame 执行动画，最大优势是能保证动画帧回调队列中的回调函数在屏幕每一次刷新前都被执行一次，然后将结果一起重绘到浏览器页面，这样就不会引起丢帧，动画也就不会卡顿。
requestAnimationFrame() 只有当标签页处于活跃状态是才会执行，当页面隐藏或最小化时，会被暂停，页面显示，会继续执行，节省了 CPU 开销。早期浏览器会对切换至后台或不活跃的标签页中的计时器执行限流，导致计时器时间不精确，此外计时器在后台仍会进行计时工作，执行动画任务，此时刷新动画是完全没有意义的。
 */
//tip： 不建议在 requestIdleCallback 里再操作 DOM，这样会导致页面再次重绘。DOM 操作建议在 requestAnimationFrame 中进行
// 辅助函数，查看当前帧是否还有时间执行任务，没有时间就下一次再执行
// 如果时间计算时间太长，其实也没卵用

function _runTask(task: Function, callback: Function) {
    //requestIdleCallback 兼容上没有requestAnimationFrame好
    // 在google，safari浏览器实测，当打开调试工具，代码一直在运行，导致页面奔溃,因为根本进不了< 16.6。
    // 不开调试工具时，safari会执行完，且不卡顿。google不行，越来越卡
    // let start = Date.now()
    // requestAnimationFrame(() => {
    //     const time = Date.now() - start
    //     console.log(time)
    //     if (time < 16.6) {
    //         task()
    //         callback(true)
    //     } else {
    //         console.log(123)
    //          _runTask(task, callback)
    //      }
        
    // })
    // requestAnimationFrame 的回调函数会在浏览器每一帧开始渲染前被调用，与渲染同步
    // requestIdleCallback是在浏览器空闲时段执行
    // safari不支持这个玩意
    requestIdleCallback((idle) => {
        if (idle.timeRemaining() > 0) {
            task()
            callback()
        } else {
            _runTask(task, callback)
        }
    })
}
/*
 * 运行一个耗时任务，如果要异步执行任务，请返回promise
 * 要尽快完成任务，同时不要让页面产生卡顿
 * 尽量兼容多的浏览器
 * @param {Function} task

 */
//task 是耗时任务，在google或者edge中会多给一些时间给计算，然后渲染帧的时间会延后，导致页面卡顿
// safari中不会卡顿，该计算就计算，该渲染就渲染，计算时间就会长一点点。
export function runTask(task: Function) {
   
 // 1. 
 // task() // 直接调用，执行1000次每次5毫秒的计算会导致页面卡死
// 2. 异步任务，返回promise去计时. 卡死。微任务也要全部执行完才渲染
    // return new Promise((resolve) => {
    //         Promise.resolve().then(() => {
    //             task()
    //             resolve(true)
    //         })
    //     })
 //   3. setTimeout 宏任务 卡顿，但是不卡死。
 // 是因为每次浏览器自己判断渲染时机，google每一帧会匀一部分时间给计算。总时长6s
 // 但是safari不会卡顿，优先渲染，总的计算时间就会长一些，到达7s以上
//  return new Promise((resolve) => {
//     setTimeout(() => {
//         task()
//         resolve(true)
//     }, 0)
//     })
// 4. 直接使用requestAnimationFrame，也是会卡死。在那一帧，执行了1000个任务
//  return new Promise((resolve) => {
//     requestAnimationFrame(() => {
//         task()
//         resolve(true)
//     })
//     })
// 5. 由上我们得到启发，分给每一帧去计算一个任务
  // 这里返回promise不重要，是题目为了计时用
    return new Promise((resolve) => {
        _runTask(task, resolve)
    })

}